﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace LightingServer.TCP
{
    internal class ProtocolDecoder
    {
        public ProtocolData Decode(byte[] data)
        {
            ProtocolData protocolData = null;
            MemoryStream stream = null;
            for (int i = 0; i < data.Length; i++)
            {
                byte value = data[i];

                switch (value)
                {
                    case ProtocolData.Head:
                        stream = new MemoryStream();
                        break;
                    case ProtocolData.Tail:
                        stream.Position = 0;
                        protocolData = Decode(stream);
                        stream = null;
                        break;
                    default:
                        if (stream != null)
                        {
                            stream.WriteByte(data[i]);
                        }
                        break;
                }
            }
            return protocolData;
        }

        public ProtocolData Decode(MemoryStream stream)
        {
            ProtocolData protocol = new ProtocolData();
            using (stream)
            {
                byte header0 = this.Read(stream);
                byte header1 = this.Read(stream);
                protocol.CommandID = (ushort)((header0 << 8) + header1);

                byte header2 = this.Read(stream);
                byte header3 = this.Read(stream);
                byte header4 = this.Read(stream);
                byte header5 = this.Read(stream);
                protocol.SerialNumber = (header2 << 24) + (header3 << 16) + (header4 << 8) + (header5 << 0);

                byte header6 = this.Read(stream);
                byte header7 = this.Read(stream);
                byte header8 = this.Read(stream);
                byte header9 = this.Read(stream);
                protocol.Length = (header6 << 24) + (header7 << 16) + (header8 << 8) + header9;

                List<byte> list = new List<byte>();
                while (stream.Position != stream.Length)
                {
                    list.Add(this.Read(stream));
                }

                if (protocol.Length == list.Count)
                {
                    protocol.Data = list.ToArray();
                }
            }
            return protocol;
        }

        private byte Read(MemoryStream stream)
        {
            byte value = (byte)stream.ReadByte();
            switch (value)
            {
                case ProtocolData.HeadEscape:
                    switch ((byte)stream.ReadByte())
                    {
                        case ProtocolData.HeadEscape1:
                            return ProtocolData.Head;
                        case ProtocolData.HeadEscape2:
                            return ProtocolData.HeadEscape;
                        default:
                            throw new FormatException();
                    }
                case ProtocolData.TailEscape:
                    switch ((byte)stream.ReadByte())
                    {
                        case ProtocolData.TailEscape1:
                            return ProtocolData.Tail;
                        case ProtocolData.TailEscape2:
                            return ProtocolData.TailEscape;
                        default:
                            throw new FormatException();
                    }
            }

            return value;
        }
    }
}
